import Dict
import Lenguaje
import Parser
import ByValue
import ByName
import HUnit
import Debug.Trace

def :: String -> String -> (FuncId, FuncDef)
def proto body = d (parser proto) (parser body)
  where d (Call f args) body = (f, FuncDef (map unVar args) body)
        unVar (Var x) = x

definiciones = makeDict [
                   def "sumartodos(n)"
				   "ifZero n then n \
				    \ else n + sumarTodos(n - 1)" ,
					
					def "cruzada(n)"
					      "ifZero n then 0 \
						  \ else cruzadan(n-1)",
						  
				    def "cruzadan(n)"
					     "ifZero n then 1 \
						 \ else (Let x=cruzada(n-1) in x)",
						 
				    def "colgarse(x)"
					    "colgarse(x-1)",
						
					def "andear(b,c)"
					    "ifZero b then 0 \
						\ else ifZero c then 0 \
						\ else 1",
                   def "menor(a,b)"
                       "ifZero a then (ifZero b then 1 else 0) else ifZero b then 1 else menor(a-1,b-1)",

                   def "cociente(a,b)"
                       "ifZero b then colgarse(b) \
                       \ else ifZero menor(a,b) then 0 \
                       \ else let x=cociente(a - b, b) in (1 +x) ",

                   def "resto(a,b)"
                       "ifZero b then colgarse(b) \
                       \ else ifZero menor(a,b) then a \
                       \ else let y=resto(a-b,b) in y ",
                  
                   def "ackermann(m,n)"
                       "ifZero m then n+1 \
                       \ else ifZero n then ackermann(m-1,1) \
                       \ else ackermann(m-1, ackermann(m,n-1))",

                   def "f(y)"
                        "ifZero y then 0 else let x= y in f(x-1) + y",

                   def "ceroOY(x,y)"
                        "ifZero x then x else y",

                   def "factorial(k)"
                       "ifZero k then 1 else let k=k*factorial(k-1) in k",

                   def "ff(k)"
                       "let x=colgarse(k) in k"
                   ]

                       
                   
main1 = parser "sumarTodos(sumarTodos(4))"
main2 = parser "Let x=5 in sumarTodos(sumarTodos(x))"
main3 = parser "cruzada(10)"
main4 = parser "cruzada(11)"
main5 = parser "andear(0,colgarse(2))"
main6 = parser "let j=5 in (let j=2 in j)+j"
main7 = parser "cociente(10,2)"
main8 = parser "ackermann(2,2)"
main9 = parser "resto(17,5)"
main10 = parser "f(f(4))"
main11 = parser "ceroOY(0,menor((2-3),(2-3)))"
main12 = parser "factorial(5)"
main13 = parser "ff(3)"
main14 = parser "cociente(2,1)"

testsByValue = test [ "test1" ~: "(eval definiciones main1)" ~: 55 ~=? (eval definiciones main1),
               "test2" ~: "(eval definiciones main2)" ~: 120 ~=? (eval definiciones main2),
               "test3" ~: "(eval definiciones main3)" ~: 0 ~=? (eval definiciones main3),
               "test4" ~: "(eval definiciones main4)" ~: 1 ~=? (eval definiciones main4),
               "test6" ~: "(eval definiciones main6)" ~: 7 ~=? (eval definiciones main6),
               "test7" ~: "(eval definiciones main7)" ~: 5 ~=? (eval definiciones main7),
               "test8" ~: "(eval definiciones main8)" ~: 7 ~=? (eval definiciones main8),
               "test9" ~: "(eval definiciones main9)" ~: 2 ~=? (eval definiciones main9),
               "test10" ~: "(eval definiciones main10)" ~: 55 ~=? (eval definiciones main10),
               "test12" ~: "(eval definiciones main12)" ~: 120 ~=? (eval definiciones main12)]

testsByName = test [ "test1" ~: "(reduce definiciones main1)" ~: 55 ~=? (reduce definiciones main1),
               "test2" ~: "(reduce definiciones main2)" ~: 120 ~=? (reduce definiciones main2),
               "test3" ~: "(reduce definiciones main3)" ~: 0 ~=? (reduce definiciones main3),
               "test4" ~: "(reduce definiciones main4)" ~: 1 ~=? (reduce definiciones main4),
               "test6" ~: "(reduce definiciones main6)" ~: 7 ~=? (reduce definiciones main6),
               "test7" ~: "(reduce definiciones main7)" ~: 5 ~=? (reduce definiciones main7),
               "test8" ~: "(reduce definiciones main8)" ~: 7 ~=? (reduce definiciones main8),
               "test9" ~: "(reduce definiciones main9)" ~: 2 ~=? (reduce definiciones main9),
               "test10" ~: "(eval definiciones main10)" ~: 55 ~=? (reduce definiciones main10),
               "test12" ~: "(eval definiciones main12)" ~: 120 ~=? (reduce definiciones main12),
               "test5" ~: "(eval definiciones main5)" ~: 0 ~=? (reduce definiciones main5 ),
               "test11" ~: "(eval definiciones main11)" ~: 0 ~=? (reduce definiciones main11 ),
               "test13" ~: "(eval definiciones main13)" ~: 3 ~=? (reduce definiciones main13 )]

diccionario = makeDict [("hola","fonola"),("fernet", "con coca"),("plp", "ojala sea promocionable")]
dictVacio :: Dict Int Int
dictVacio = emptyDict
testDict1 = (Nothing == (lookupDict dictVacio 3))
testDict2 = (Just "fonola" == (lookupDict diccionario "hola"))
testDict3 = (Just "con coca" == (lookupDict diccionario "fernet"))
testDict4 = (Nothing == (lookupDict (removeDict diccionario "hola") "hola"))
testDict5 = (Just "vecinillo" == (lookupDict (extendDict diccionario "hola" "vecinillo") "hola"))
testDict6 = (Nothing == (lookupDict diccionario "tito"))
testDict7 = (Just "perez" == (lookupDict (extendDict diccionario "tito" "perez") "tito"))
testDict8 = (Just "como va" == (lookupDict (extendDict (removeDict diccionario "hola") "hola" "como va") "hola"))
testsDict = (all id [testDict1, testDict2, testDict3, testDict4, testDict5, testDict6, testDict7, testDict8])
                    
--para correrlos hace runTestTT tests
-- Tests que en byValue deben tildarse
test5 = (eval definiciones main5) -- en byName debe dar 0
test11 = (eval definiciones main11) -- en byName debe dar 0
test13 = (eval definiciones main13) -- en byName debe dar 3
fede = reduce definiciones (Const 10)
